package com.hansion.h_ble; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.os.Handler; import android.os.Looper; import android.util.Log; import com.hansion.h_ble.callback.BleDeviceScanCallback; import com.hansion.h_ble.callback.ConnectCallback; import com.hansion.h_ble.callback.OnReceiverCallback; import com.hansion.h_ble.callback.OnWriteCallback; import com.hansion.h_ble.callback.ScanCallback; import com.hansion.h_ble.request.ReceiverRequestQueue; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; /** * Description: * Author: Hansion www.hansion.win * Time: 2017/2/13 9:43 */ public class BleController { private static String LOGTAG = "H_Ble_Lib --> "; //BleCOntroller实例 private static BleController sBleManager; private Context mContext; private BluetoothManager mBluetoothManager; private BluetoothAdapter mAdapter; private BluetoothGatt mBluetoothGatt; private BluetoothGattCharacteristic gattCharacteristic; private BleGattCallback mGattCallback; private OnWriteCallback writeCallback; private Handler mHandler = new Handler(Looper.getMainLooper()); //发起连接是否有响应 private boolean isConnectResponse = false; //获取到所有服务的集合 private HashMap<String, Map<String, BluetoothGattCharacteristic>> servicesMap = new HashMap<>(); //默认扫描时间:5s private static final int SCAN_TIME = 5000; //默认连接超时时间:6s private static final int CONNECTION_TIME_OUT = 6000; //是否是用户手动断开 private boolean isBreakByMyself = false; //连接结果的回调 private ConnectCallback connectCallback; //读操作请求队列 private ReceiverRequestQueue mReceiverRequestQueue = new ReceiverRequestQueue(); //此属性一般不用修改 private static final String BLUETOOTH_NOTIFY_D = "00002902-0000-1000-8000-00805f9b34fb"; //TODO 这里是硬件提供的各种UUID 一定要根据自己的情况进行修改 private static final String BLUETOOTH_S = "0000fff0-0000-1000-8000-00805f9b34fb"; private static final String BLUETOOTH_NOTIFY_C = "0000fff7-0000-1000-8000-00805f9b34fb"; private static final String BLUETOOTH_WRITE_C = "0000fff6-0000-1000-8000-00805f9b34fb"; //----------------------------- 对外公开的方法 ---------------------------------------------- /** * 获取BleController实例对象 * @return */ public synchronized static BleController getInstance() { if (null == sBleManager) { sBleManager = new BleController(); } return sBleManager; } /** * 进行初始化 * @param context * @return */ public BleController init(Context context) { if (mContext == null) { mContext = context.getApplicationContext(); mBluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE); if (null == mBluetoothManager) { Log.e(LOGTAG, "BluetoothManager init error!"); } mAdapter = mBluetoothManager.getAdapter(); if (null == mAdapter) { Log.e(LOGTAG, "BluetoothManager init error!"); } mGattCallback = new BleGattCallback(); } return this; } /** * 扫描设备 * 当传入的time值为0以下时默认扫描时间为5秒 */ public void scanBle(int time, final ScanCallback scanCallback) { if (!isEnable()) { mAdapter.enable(); Log.e(LOGTAG, "Bluetooth is not open!"); } if (null != mBluetoothGatt) { mBluetoothGatt.close(); } reset(); final BleDeviceScanCallback bleDeviceScanCallback = new BleDeviceScanCallback(scanCallback); mHandler.postDelayed(new Runnable() { @Override public void run() { //time后停止扫描 mAdapter.stopLeScan(bleDeviceScanCallback); scanCallback.onSuccess(); } }, time <= 0 ? SCAN_TIME : time); mAdapter.startLeScan(bleDeviceScanCallback); } /** * 连接设备 * * @param connectionTimeOut 连接超时时间,默认是6秒.当赋值为0或更小值时用默认值 * @param devicesAddress 想要连接的设备地址 */ public void connect(final int connectionTimeOut, final String devicesAddress, ConnectCallback connectCallback) { BluetoothDevice remoteDevice = mAdapter.getRemoteDevice(devicesAddress); if (null == remoteDevice) { Log.e(LOGTAG, "No device found at this address:" + devicesAddress); return; } this.connectCallback = connectCallback; if (null != mBluetoothGatt) { mBluetoothGatt.close(); } reset(); mBluetoothGatt = remoteDevice.connectGatt(mContext, false, mGattCallback); Log.e(LOGTAG, "connecting mac-address:" + devicesAddress); delayConnectResponse(connectionTimeOut); } /** * 发送数据 * * @param buf * @param writeCallback */ public void writeBuffer(byte[] buf, OnWriteCallback writeCallback) { this.writeCallback = writeCallback; if (!isEnable()) { writeCallback.onFailed(OnWriteCallback.FAILED_BLUETOOTH_DISABLE); Log.e(LOGTAG, "FAILED_BLUETOOTH_DISABLE"); return; } if (gattCharacteristic == null) { gattCharacteristic = getBluetoothGattCharacteristic(BLUETOOTH_S, BLUETOOTH_WRITE_C); } if (null == gattCharacteristic) { writeCallback.onFailed(OnWriteCallback.FAILED_INVALID_CHARACTER); Log.e(LOGTAG, "FAILED_INVALID_CHARACTER"); return; } //设置数组进去 gattCharacteristic.setValue(buf); //发送 boolean b = mBluetoothGatt.writeCharacteristic(gattCharacteristic); Log.e(LOGTAG, "send:" + b + "data:" + bytesToHexString(buf)); } /** * 设置读取数据的监听 * * @param requestKey * @param onReceiverCallback */ public void registReciveListener(String requestKey, OnReceiverCallback onReceiverCallback) { mReceiverRequestQueue.set(requestKey, onReceiverCallback); } /** * 移除读取数据的监听 * * @param requestKey */ public void unregistReciveListener(String requestKey) { mReceiverRequestQueue.removeRequest(requestKey); } /** * 手动断开Ble连接 */ public void closeBleConn() { disConnection(); isBreakByMyself = true; gattCharacteristic = null; mBluetoothManager = null; } //---------------------------------- 私有方法 ---------------------------------------------- /** * 将byte数组转为16进制字符串 此方法主要目的为方便Log的显示 */ public String bytesToHexString(byte[] src) { StringBuilder stringBuilder = new StringBuilder(""); if (src == null || src.length <= 0) { return null; } for (byte aSrc : src) { int v = aSrc & 0xFF; String hv = Integer.toHexString(v); if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv.toUpperCase()).append(" "); } return stringBuilder.toString(); } /** * 当前蓝牙是否打开 */ private boolean isEnable() { if (null != mAdapter) { return mAdapter.isEnabled(); } return false; } /** * 复位 */ private void reset() { isConnectResponse = false; servicesMap.clear(); } /** * 如果连接connectionTimeOut时间后还没有响应,手动关掉连接. * * @param connectionTimeOut */ private void delayConnectResponse(int connectionTimeOut) { mHandler.removeCallbacksAndMessages(null); mHandler.postDelayed(new Runnable() { @Override public void run() { if (!isConnectResponse && !isBreakByMyself) { Log.e(LOGTAG, "connect timeout"); disConnection(); reConnect(); } else { isBreakByMyself = false; } } }, connectionTimeOut <= 0 ? CONNECTION_TIME_OUT : connectionTimeOut); } /** * 断开连接 */ private void disConnection() { if (null == mAdapter || null == mBluetoothGatt) { Log.e(LOGTAG, "disconnection error maybe no init"); return; } mBluetoothGatt.disconnect(); reset(); } /** * 蓝牙GATT连接及操作事件回调 */ private class BleGattCallback extends BluetoothGattCallback { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (newState == BluetoothProfile.STATE_CONNECTED) { //连接成功 isBreakByMyself = false; mBluetoothGatt.discoverServices(); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { //断开连接 if (!isBreakByMyself) { reConnect(); } reset(); } } //服务被发现了 @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (null != mBluetoothGatt && status == BluetoothGatt.GATT_SUCCESS) { List<BluetoothGattService> services = mBluetoothGatt.getServices(); int serviceSize = services.size(); for (int i = 0; i < serviceSize; i++) { HashMap<String, BluetoothGattCharacteristic> charMap = new HashMap<>(); BluetoothGattService bluetoothGattService = services.get(i); String serviceUuid = bluetoothGattService.getUuid().toString(); List<BluetoothGattCharacteristic> characteristics = bluetoothGattService.getCharacteristics(); int characteristicSize = characteristics.size(); for (int j = 0; j < characteristicSize; j++) { charMap.put(characteristics.get(j).getUuid().toString(), characteristics.get(j)); if (characteristics.get(j).getUuid().toString().equals(BLUETOOTH_NOTIFY_C)) { if (enableNotification(true, characteristics.get(j))) { isConnectResponse = true; connSuccess(); } else { reConnect(); } } } servicesMap.put(serviceUuid, charMap); } // TODO 打印搜索到的服务 // printServices(mBluetoothGatt); } } //收到数据 @Override public void onCharacteristicChanged(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) { if (null != mReceiverRequestQueue) { HashMap<String, OnReceiverCallback> map = mReceiverRequestQueue.getMap(); final byte[] rec = characteristic.getValue(); for (String key : mReceiverRequestQueue.getMap().keySet()) { final OnReceiverCallback onReceiverCallback = map.get(key); runOnMainThread(new Runnable() { @Override public void run() { onReceiverCallback.onRecive(rec); } }); } } } //描述符被写了 @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { } //描述符被读了 @Override public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { } //发送数据结果 @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { if (null != writeCallback) { if (status == BluetoothGatt.GATT_SUCCESS) { runOnMainThread(new Runnable() { @Override public void run() { writeCallback.onSuccess(); } }); Log.e(LOGTAG, "Send data success!"); } else { runOnMainThread(new Runnable() { @Override public void run() { writeCallback.onFailed(OnWriteCallback.FAILED_OPERATION); } }); Log.e(LOGTAG, "Send data failed!"); } } } } private boolean enableNotification(boolean enable, BluetoothGattCharacteristic characteristic) { if (mBluetoothGatt == null || characteristic == null) return false; if (!mBluetoothGatt.setCharacteristicNotification(characteristic, enable)) return false; BluetoothGattDescriptor clientConfig = characteristic.getDescriptor(UUID.fromString(BLUETOOTH_NOTIFY_D)); if (clientConfig == null) return false; if (enable) { clientConfig.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); } else { clientConfig.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE); } return mBluetoothGatt.writeDescriptor(clientConfig); } //打印所有搜索到的服务 此方法用于硬件方未提供UUID时查询所有UUID private void printServices(BluetoothGatt gatt) { if (gatt != null) { Iterator i$ = gatt.getServices().iterator(); while (i$.hasNext()) { BluetoothGattService service = (BluetoothGattService) i$.next(); Log.i(LOGTAG, "service: " + service.getUuid()); Iterator i$1 = service.getCharacteristics().iterator(); while (i$1.hasNext()) { BluetoothGattCharacteristic characteristic = (BluetoothGattCharacteristic) i$1.next(); Log.d("LOGTAG", " characteristic: " + characteristic.getUuid() + " value: " + Arrays.toString(characteristic.getValue())); Iterator i$2 = characteristic.getDescriptors().iterator(); while (i$2.hasNext()) { BluetoothGattDescriptor descriptor = (BluetoothGattDescriptor) i$2.next(); Log.v("LOGTAG", " descriptor: " + descriptor.getUuid() + " value: " + Arrays.toString(descriptor.getValue())); } } } } } /** * 根据服务UUID和特征UUID,获取一个特征{@link BluetoothGattCharacteristic} * * @param serviceUUID 服务UUID * @param characterUUID 特征UUID */ private BluetoothGattCharacteristic getBluetoothGattCharacteristic(String serviceUUID, String characterUUID) { if (!isEnable()) { throw new IllegalArgumentException(" Bluetooth is no enable please call BluetoothAdapter.enable()"); } if (null == mBluetoothGatt) { Log.e(LOGTAG, "mBluetoothGatt is null"); return null; } //找服务 Map<String, BluetoothGattCharacteristic> bluetoothGattCharacteristicMap = servicesMap.get(serviceUUID); if (null == bluetoothGattCharacteristicMap) { Log.e(LOGTAG, "Not found the serviceUUID!"); return null; } //找特征 Set<Map.Entry<String, BluetoothGattCharacteristic>> entries = bluetoothGattCharacteristicMap.entrySet(); BluetoothGattCharacteristic gattCharacteristic = null; for (Map.Entry<String, BluetoothGattCharacteristic> entry : entries) { if (characterUUID.equals(entry.getKey())) { gattCharacteristic = entry.getValue(); break; } } return gattCharacteristic; } private void runOnMainThread(Runnable runnable) { if (isMainThread()) { runnable.run(); } else { if (mHandler != null) { mHandler.post(runnable); } } } private boolean isMainThread() { return Looper.myLooper() == Looper.getMainLooper(); } // TODO 此方法断开连接或连接失败时会被调用。可在此处理自动重连,内部代码可自行修改,如发送广播 private void reConnect() { if(connectCallback != null) { runOnMainThread(new Runnable() { @Override public void run() { connectCallback.onConnFailed(); } }); } Log.e(LOGTAG, "Ble disconnect or connect failed!"); } // TODO 此方法Notify成功时会被调用。可在通知界面连接成功,内部代码可自行修改,如发送广播 private void connSuccess() { if(connectCallback != null) { runOnMainThread(new Runnable() { @Override public void run() { connectCallback.onConnSuccess(); } }); } Log.e(LOGTAG, "Ble connect success!"); } }